package sampledb

import javax.sql.DataSource
import sweet.helper._
import sweet.helper.jdbc._
import sweet.mvc.api._
import sweet.helper.mail._

class Feedback{
  var id: Int = _
  var userId: Int = _
  var parentId: Int = _
  var author: String = _
  var message: String = _
  var createdDate: java.util.Date = _
  var isPrivate: Boolean = false
}
class FeedbackDao(val dataSource: DataSource) extends Logger with JdbcSupport{
  def save(feedback: Feedback): Int = {
    logger.debug("Saving new feedback" +feedback)
    withTxJdbc{ tx=>
      tx.update("insert into feedback(parent_id, user_id, author, message, is_private, created_date) values(?,?,?,?,?, now())", 
        feedback.parentId, feedback.userId, feedback.author, feedback.message, feedback.isPrivate)
      feedback.id = tx.queryInt("select last_insert_id()")
    }
    feedback.id
  }
  
  /** Return (pageList, totalSize). page param is 1 base index. */
  def pagingFeedbacks(currentPage: Int, toPage: String, rowsPerPage: Int): (List[Feedback], Int, Int, Int) = {
    logger.debug("Paging feedbacks: currentPage "+currentPage+", toPage "+toPage+", rowsPerPage "+rowsPerPage)
    
    val res = new scala.collection.mutable.ListBuffer[Feedback]
    var totalRows = queryInt("select count(*) from feedback where is_private=0")
    var totalPages = totalRows / rowsPerPage + 1
    val toPageNum =  toPage match {
      case "first" =>1
      case "prev" => if(currentPage<=1) 1 else currentPage - 1
      case "next" => if(currentPage>=totalPages) totalPages else currentPage + 1
      case "last" => totalPages
      case n@_ => { 
        val pn = n.toInt
        if(pn>=totalPages) totalPages 
        else 
          if(pn<=1) 1 else pn
      }
    }
    logger.debug("TotalRows "+totalRows+", totalPages "+ totalPages+", toPageNum "+toPageNum)
    
    val lstart = (toPageNum - 1) * rowsPerPage
    val lend = lstart + rowsPerPage
    logger.debug("limit lstart "+lstart+", lend "+lend)
    query("select * from feedback where is_private=0 order by created_date desc, id desc limit ?,?",lstart, lend){ rsh =>
      val rs = rsh.rs
      val feedback = new Feedback
      feedback.id = rs.getInt("id")
      feedback.userId = rs.getInt("user_id")
      feedback.parentId = rs.getInt("parent_id")
      feedback.author = rs.getString("author")
      feedback.message = rs.getString("message")
      feedback.createdDate = rs.getTimestamp("created_date")
      feedback.isPrivate = rs.getBoolean("is_private")
      res += feedback
    }
    (res.toList, totalPages, totalRows, toPageNum)
  }
}

class FeedbackController(notifyEmail: String, emailSender: EmailSender, feedbackDao: FeedbackDao) extends FormController{
  handle("/index"){ View("redirect:/post") }
  
  val form = new Form("feedback"){
    addField("author", "Your Name/Email", StringConverter){
      VOptional()++VLen(1, 35, "We only accept name between 1 to 35 characters.")
    }    
    addMultiValuesField("private", "", StringConverter, VOptional()){
      OrderedMap("Do not show my message to public"->"private")
    }
    addField("message", "Your Feedback", StringConverter){
      VRequired()++VLen(1, 2048, "We only accept feedback message between 1 to 2048 characters.")
    }
    
    override def initialFieldValue(field: Field, formData: FormData, req: Req) = {
      if(field.name=="author"){
        val userOpt = req.sess.attr("user")
        if(userOpt != None)
          userOpt.get.asInstanceOf[User].email
        else
          "Anonymous"
      }else{ super.initialFieldValue(field, formData, req) }
    }
    override def initialFieldValue(multiValName: String, field: Field, formData: FormData, req: Req) = {
      if(field.name=="private"){ //default checks it.
        "private"
      }else{ super.initialFieldValue(field, formData, req) }
    }
  }
  
  handleForm("/post", form){ 
    new FormHandler(){
      def viewForm(formData: FormData, req: Req) =  View("/post")
      def processForm(formData: FormData, req: Req) = {
        val feedback = new Feedback
        feedback.author = formData("author")
        feedback.message = formData("message")
        logger.debug(">>> "+formData.multiValues("private"))
        feedback.isPrivate = if(formData.multiValues("private").size==1) true else false
        
        val userOpt = req.sess.attr("user")
        if(userOpt != None)
          feedback.userId = userOpt.get.asInstanceOf[User].id
        
        logger.debug("Saving a feedback msg from "+feedback.author +" userId "+feedback.userId)
        feedbackDao.save(feedback)
        logger.debug("Feedback saved id " + feedback.id)
        
        //send email to notifyEmail for a new feedback.
        val authorExtra = if(userOpt != None) " (user_id="+feedback.userId+")" else ""
        emailSender.send(notifyEmail, "New Feedback Message from "+feedback.author+authorExtra, feedback.message)
                
        View("/thankyou")
      }
    }
  }
  
  val ROWS_PER_PAGE = 50
  handleReq("/view"){ req =>    
    val currentPage = req.param("currentPage", "1").toInt //current page
    val toPage = req.param("toPage", "1")
    
    //get list, pagecount, totalsize
    val (feedbacks, totalPages, totalRows, toPageNum) = feedbackDao.pagingFeedbacks(currentPage, toPage, ROWS_PER_PAGE)
    //masked out the email
    for(fb <- feedbacks)
    if(fb.author.contains("@")){
      fb.author = fb.author.replaceAll("@", " at ")
      fb.author = fb.author.replaceAll("\\.", " dot ")
    }
    
    View("/view", "feedbacks"->feedbacks, "currentPage"->toPageNum, "totalPages"->totalPages, "totalRows"->totalRows, "rowsPerPage"->ROWS_PER_PAGE)  
  }
}

